package com.demo.dao;

import java.io.Serializable;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

@Repository
public class BaseDAO extends HibernateDaoSupport
{
	public final static int MAX_TAG_COUNT = 5;
	public final static int MAX_TAG_LENGTH = 20;
	public Log logger = LogFactory.getLog(this.getClass());
	private static Transaction tx = null;
	
	
	/*
	 * 注入session factory
	 */
	@Autowired
	public void setSF(SessionFactory sessionFactory) {
		setSessionFactory(sessionFactory);
	}
	
	/**
	 * 
	 * 
	 * @return
	 */
	public HibernateTemplate getCacheHT()
	{
		HibernateTemplate ht = super.getHibernateTemplate();
		ht.setCacheQueries(true);
		return ht;
	}

	/**
	 * 
	 * 
	 * @param o
	 * @return
	 */
	public Object makePersistant(Object o)
	{
		Session sess = this.getSession();
		sess.saveOrUpdate(o);
		this.releaseSession(sess);
		return o;
	}

	/**
	 * 
	 * 
	 * @param cbean
	 */
	protected boolean saveOrUpdate(Object obj)
	{
		boolean flag = true;
		try
		{
			HibernateTemplate ht = this.getCacheHT();
			ht.saveOrUpdate(obj);
		}
		catch (HibernateException e)
		{
			logger.error(e);
			flag = false;
		}
		return flag;
	}

	public void closeSession()
	{
		this.getSession().close();
	}

	public boolean saveObj(Object obj)
	{
		boolean flag = true;
		
		Session sess = null;
		try
		{
			sess = this.getSession();
			sess.save(obj);
		}
		catch(Exception e)
		{
			flag = false;
			e.printStackTrace();
		}
		finally
		{
			if(sess != null) this.releaseSession(sess);
		}
		
		return flag;
	}
	
	public boolean saveOrUpdateObj(Object obj)
	{
		boolean flag = true;
		
		Session sess = null;
		try
		{
			sess = this.getSession();
			sess.saveOrUpdate(obj);
		}
		catch(Exception e)
		{
			flag = false;
			e.printStackTrace();
		}
		finally
		{
			if(sess != null) this.releaseSession(sess);
		}
		
		return flag;
	}

	/**
	 * 
	 * 
	 * @param objs
	 * @return
	 */
	protected boolean saveOrUpdateAll(Object[] objs)
	{
		boolean flag = true;
		try
		{
			tx = getSession().beginTransaction();
			for (int i = 0; i < objs.length; i++)
			{
				getSession().saveOrUpdate(objs[i]);
			}
			tx.commit();
			this.releaseSession(getSession());
		}
		catch (HibernateException e)
		{
			if (tx != null)
				tx.rollback();
			flag = false;
		}
		finally
		{
			closeSession();
		}
		return flag;
	}

	/**
	 * public boolean updateObj(Object obj) { boolean flag = true; try { Session
	 * ssn = this.getSession(); tx = getSession().beginTransaction();
	 * ssn.update(obj); tx.commit(); } catch (HibernateException e) { if (tx !=
	 * null) tx.rollback(); flag = false; } finally { closeSession(); } return
	 * flag; }
	 * 
	 * /** 
	 * 
	 * @param cbean
	 */
	public boolean delete(Object cbean)
	{
		boolean flag = true;
		
		Session session = null;
		if(cbean != null)
		{
			try
			{
				session = getSession();
				tx = session.beginTransaction();
				session.delete(cbean);
				tx.commit();
			}
			catch (Exception e)
			{
				if (tx != null) tx.rollback();
				flag = false;
				e.printStackTrace();
			}
			finally
			{
				if(session != null) this.releaseSession(session);
			}
		}
		
		
		return flag;
	}

	/**
	 * 
	 * 
	 * @param objClass
	 * @param key
	 * @return
	 */
	protected int delete(Class objClass, Serializable key)
	{
		StringBuffer hql = new StringBuffer("DELETE FROM ");
		hql.append(objClass.getName());
		hql.append(" AS t WHERE t.id=?");
		return commitUpdate(hql.toString(), new Object[] { key });
	}

	protected int delete(Class objClass, int key)
	{
		return delete(objClass, new Integer(key));
	}

	/**
	 * 
	 */
	public void flush()
	{
		try
		{
			Session ssn = getSession();
			if (ssn.isDirty())
			{
				tx = ssn.beginTransaction();
				ssn.flush();
				tx.commit();
			}
			this.releaseSession(ssn);
		}
		catch (HibernateException e)
		{
			if (tx != null)
				tx.rollback();
			throw e;
		}
		finally
		{
			this.closeSession();
		}
	}

	/**
	 * 
	 * 
	 * @param beanClass
	 * @param ident
	 * @return
	 */
	protected Object getBeanById(Class beanClass, int id)
	{
		Session sess = this.getSession();
		Object obj = sess.get(beanClass, new Integer(id));
		this.releaseSession(sess);
		return obj;
	}

	protected Object getBeanById(Class beanClass, String id)
	{
		Session sess = this.getSession();
		Object obj = sess.get(beanClass, id);
		this.releaseSession(sess);
		return obj;
	}

	/**
	 * ִ
	 * 
	 * @param hql
	 * @param args
	 * @return
	 */
	protected Number executeStat(String hql, Object[] args)
	{
		return (Number) uniqueResult(hql, args);
	}

	/**
	 * ִ
	 * 
	 * @param hql
	 * @param args
	 * @return
	 */
	protected int executeStatAsInt(String hql, Object[] args)
	{
		return (executeStat(hql, args)).intValue();
	}

	protected int executeStatAsInt(String hql, int parm1)
	{
		return executeStatAsInt(hql, new Object[] { new Integer(parm1) });
	}

	protected int executeStatAsInt(String hql, int parm1, int parm2)
	{
		return executeStatAsInt(hql, new Object[] { new Integer(parm1),
				new Integer(parm2) });
	}

	protected int executeStatAsInt(String hql, int parm1, int parm2, int parm3,
			int parm4)
	{
		return executeStatAsInt(hql, new Object[] { new Integer(parm1),
				new Integer(parm2), new Integer(parm3), new Integer(parm4) });
	}

	/**
	 * ִ
	 * 
	 * @param hql
	 * @param args
	 * @return
	 */
	protected long executeStatAsLong(String hql, Object[] args)
	{
		return (executeStat(hql, args)).longValue();
	}

	/**
	 *
	 * 
	 * @param hql
	 * @param args
	 * @return
	 */
	protected List findAll(String hql, Object[] args)
	{
		return executeQuery(hql, -1, -1, args);
	}
	
	protected List findAllBySQL(String sql, Object[] args)
	{
		return executeQueryBySQL(sql, -1, -1, args);
	}
	
	/**
	 * 
	 * 
	 * @param hql
	 * @param condParm1
	 * @param condParm2
	 * @param parm1
	 * @param parm2
	 * @return
	 */
	protected List findAllByList(String hql, String condParm1,
			String condParm2, List parm1, int parm2)
	{
		Session ssn = this.getSession();
		Query q = ssn.createQuery(hql);
		q.setParameterList(condParm1, parm1);
		q.setInteger(condParm2, parm2);
		List l = q.list();
		this.releaseSession(ssn);
		if (l == null || l.isEmpty())
			return null;
		return l;

	}

	protected void removeByList(String hql, String condParm1, String condParm2,
			List parm1, int parm2)
	{
		Session ssn = this.getSession();
		Query q = ssn.createQuery(hql);
		q.setParameterList(condParm1, parm1);
		q.setInteger(condParm2, parm2);
		q.executeUpdate();
		this.releaseSession(ssn);
	}

	
	protected List executeQuery(String hql, int fromIdx, int fetchCount, Object[] parameterArray)
	{
		List queryList = null;
		Session session = this.getSession();
		try
		{
			Query query = session.createQuery(hql);
			
			for (int i = 0; parameterArray != null && i < parameterArray.length; i++)
			{
				if(parameterArray[i] instanceof List)
				{
					query.setParameterList((String)parameterArray[i+1], (List)parameterArray[i]);
					++i;
				}
				else
				{
					query.setParameter(i, parameterArray[i]);
				}
			}
			
			if (fromIdx > 0)
			{
				query.setFirstResult(fromIdx);
			}
				
			if (fetchCount > 0)
			{
				query.setMaxResults(fetchCount);
			}
			queryList = query.list();
			
			if (queryList != null && queryList.isEmpty())	
			{
				queryList = null;
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			this.releaseSession(session);
		}
		
		return queryList;
	}

	protected List executeQueryBySQL(String sql, int fromIdx, int fetchCount, Object[] parameterArray)
	{
		List queryList = null;
		
		Session session = this.getSession();
		try
		{
			Query query = session.createSQLQuery(sql);
			for (int i = 0; parameterArray != null && i < parameterArray.length; i++)
			{
				if(parameterArray[i] instanceof List)
				{
					query.setParameterList((String)parameterArray[i+1], (List)parameterArray[i]);
					++i;
				}
				else
				{
					query.setParameter(i, parameterArray[i]);
				}
			}
			
			if (fromIdx > 0)
			{
				query.setFirstResult(fromIdx);
			}
				
			if (fetchCount > 0)
			{
				query.setMaxResults(fetchCount);
			}
			queryList = query.list();
			
			if (queryList != null && queryList.isEmpty())	
			{
				queryList = null;
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			this.releaseSession(session);
		}
		
		return queryList;
	}
	
	protected List executeQuery(String hql, int fromIdx, int fetchCount,
			int parm1)
	{
		return executeQuery(hql, fromIdx, fetchCount,
				new Object[] { new Integer(parm1) });
	}

	protected List executeQuery(String hql, int fromIdx, int fetchCount,
			int parm1, int parm2)
	{
		return executeQuery(hql, fromIdx, fetchCount, new Object[] {
				new Integer(parm1), new Integer(parm2) });
	}

	protected List executeQuery(String hql, int fromIdx, int fetchCount,
			int parm1, int parm2, int parm3)
	{
		return executeQuery(hql, fromIdx, fetchCount, new Object[] {
				new Integer(parm1), new Integer(parm2), new Integer(parm3) });
	}

	/**
	 * ִ
	 * 
	 * @param hql
	 * @param args
	 * @return
	 */
	protected int executeUpdate(String hql, Object[] args)
	{
		Session ssn = getSession();
		Query q = ssn.createQuery(hql);
		for (int i = 0; args != null && i < args.length; i++)
		{
			q.setParameter(i, args[i]);
		}
		int i = q.executeUpdate();
		this.releaseSession(ssn);
		return i;
	}

	protected int executeUpdate(String hql, int parm1)
	{
		return executeUpdate(hql, new Object[] { new Integer(parm1) });
	}

	/**
	 * ִ
	 * 
	 * @param hql
	 * @param args
	 * @return
	 */
	protected int commitUpdate(String hql, Object[] args)
	{
		try
		{
			Session ssn = getSession();
			tx = ssn.beginTransaction();
			Query q = ssn.createQuery(hql);
			for (int i = 0; args != null && i < args.length; i++)
			{
				q.setParameter(i, args[i]);
			}
			int er = q.executeUpdate();
			tx.commit();
			this.releaseSession(ssn);
			return er;
		}
		catch (HibernateException e)
		{
			if (tx != null)
				tx.rollback();
			throw e;
		}
		finally
		{
			this.closeSession();
		}
	}

	protected int commitUpdate(String hql, int parm1, int parm2)
	{
		return commitUpdate(hql, new Object[] { new Integer(parm1),
				new Integer(parm2) });
	}

	/**
	 * 
	 * 
	 * @param hql
	 * @param args
	 * @return
	 */
	protected Object uniqueResult(String hql, Object[] args)
	{
		Object obj = null;
		
		Session ssn = this.getSession();
		try
		{
			Query q = ssn.createQuery(hql);
			for (int i = 0; args != null && i < args.length; i++)
			{
				if(args[i] instanceof List)
				{
					q.setParameterList((String)args[i+1], (List)args[i]);
					++i;
				}
				else
				{
					q.setParameter(i, args[i]);
				}
			}
			q.setMaxResults(1);
			obj = q.uniqueResult();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			this.releaseSession(ssn);
		}

		return obj;
	}
	
	protected Object uniqueResult(String hql, String parm1)
	{
		return uniqueResult(hql, new Object[] { parm1 });
	}

	/**
	 * 
	 * 
	 * @param hql
	 * @param args
	 * @return
	 */
	protected List executeQueryCacheable(String cache, String hql, int fromIdx,
			int fetchCount, Object[] args)
	{
		Session ssn = getSession();
		Query q = ssn.createQuery(hql).setCacheable(true);
		if (cache != null)
			q.setCacheRegion(cache);
		for (int i = 0; args != null && i < args.length; i++)
		{
			q.setParameter(i, args[i]);
		}
		if (fromIdx > 0)
			q.setFirstResult(fromIdx);
		if (fetchCount > 0)
			q.setMaxResults(fetchCount);
		List l = q.list();
		this.releaseSession(ssn);
		if (l == null || l.isEmpty())
			return null;
		return l;
	}

	protected List findAllCacheable(String cache, String hql, Object[] args)
	{
		return executeQueryCacheable(cache, hql, -1, -1, args);
	}

	public boolean update(Object obj)
	{
		boolean flag = true;
		
		Session sess = null;
		try
		{
			sess = this.getSession();
			tx = sess.beginTransaction();
			sess.update(obj);
			tx.commit();
		}
		catch (Exception e)
		{
			flag = false;
			if (tx != null)	tx.rollback();
			e.printStackTrace();
		}
		finally
		{
			if(sess != null) this.releaseSession(sess);
		}
		
		return flag;
	}

}
